package com.excel.read;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class ExcelUtils<T> {
    private List<Map<String, String>> list = new LinkedList<>();
    private Map<String, String> headers = new LinkedHashMap<>();

    private List<T> data = new LinkedList<>();

    private Workbook workbook;

    private ExcelCallBack<T> excelCallBack;


    private ExcelUtils(String path, ExcelCallBack<T> excelCallBack) {
        this.excelCallBack = excelCallBack;
        try {
            if (path.endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(new File(path));
            }
            if (path.endsWith(".xls")) {
                POIFSFileSystem poifsFileSystem = new POIFSFileSystem(Files.newInputStream(Paths.get(path)));
                workbook = new HSSFWorkbook(poifsFileSystem);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> ExcelUtils<T> read(String path, ExcelCallBack<T> excelCallBack) {
        try {
            ExcelUtils<T> excelUtils = new ExcelUtils<>(path, excelCallBack);
            excelUtils.read();
            return excelUtils;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void read() throws IOException {
        if (workbook != null) {
            int countSheet = workbook.getNumberOfSheets();
            for (int k = 0; k < countSheet; k++) {
                Sheet sheet = workbook.getSheetAt(k);
                read(sheet);
            }
            workbook.close();
        }
    }

    private void read(Sheet sheet) {
        try {
            int rowStart = sheet.getFirstRowNum();
            int rowEnd = sheet.getLastRowNum();
            if (rowStart == rowEnd) {
                return;
            }
            Row firstRow = sheet.getRow(rowStart);
            int cellStart = firstRow.getFirstCellNum();
            int cellEnd = firstRow.getLastCellNum();
            headers.clear();
            Map<String, String> header = new LinkedHashMap<>();
            for (int j = cellStart; j < cellEnd; j++) { //获取表头
                String value = getValue(firstRow.getCell(j), rowStart, j, workbook, true);
                if (excelCallBack != null) {
                    excelCallBack.readHeader(rowStart, j, value, header);
                }
            }
            list.clear();
            for (int i = rowStart + 1; i <= rowEnd; i++) {
                Row eachRow = sheet.getRow(i);
                Map<String, String> map = new LinkedHashMap<>();
                for (int k = cellStart; k < cellEnd; k++) {
                    if (eachRow != null) {
                        String val = getValue(eachRow.getCell(k), i, k, workbook, false);
                        if (excelCallBack != null) {
                            excelCallBack.readLine(i, k, val, map);
                        }
                    }
                }
                list.add(map);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getValue(Cell cell, int rowNum, int index, Workbook book, boolean isKey) throws IOException {
        // 空白或空
        if (cell == null || cell.getCellType() == CellType.BLANK) {
            if (isKey) {
                book.close();
                throw new NullPointerException(String.format("the key on row %s index %s is null ", ++rowNum, ++index));
            } else {
                return "";
            }
        }
        // 0. 数字 类型
        if (cell.getCellType() == CellType.NUMERIC) {
            if (DateUtil.isCellDateFormatted(cell)) {
                Date date = cell.getDateCellValue();
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format(date);
            }
            String val = cell.getNumericCellValue() + "";
            val = val.toUpperCase();
            if (val.contains("E")) {
                val = val.split("E")[0].replace(".", "");
            }
            return val;
        }
        // 1. String类型
        if (cell.getCellType() == CellType.STRING) {
            String val = cell.getStringCellValue();
            if (val == null || val.trim().length() == 0) {
                if (book != null) {
                    book.close();
                }
                return "";
            }
            return val.trim();
        }
        // 2. 公式 CELL_TYPE_FORMULA
        if (cell.getCellType() == CellType.FORMULA) {
            return cell.getStringCellValue();
        }
        // 4. 布尔类型CELL_TYPE_BOOLEAN
        if (cell.getCellType() == CellType.BOOLEAN) {
            return cell.getBooleanCellValue() + "";
        }
        // 5.  错误 CELL_TYPE_ERROR
        return "";
    }

    public final List<T> getData() {
        data.clear();
        List<Map<String, String>> list = getList();
        for (Map<String, String> map : list) {
            if (excelCallBack != null) {
                T read = excelCallBack.read(map);
                data.add(read);
            }
        }
        return data;
    }

    public final List<Map<String, String>> getList() {
        return list;
    }

    public final Map<String, String> getHeaders() {
        return headers;
    }

    public Map<String, String> getParams() {
        Map<String, String> params = new HashMap<>();
        if (excelCallBack != null) {
            params = excelCallBack.getParams();
        }
        return params;
    }

}
